package cn.phecda.boot.tenant.core.configuration;

import cn.phecda.boot.tenant.core.annotation.ConditionalOnDatabaseStrategy;
import cn.phecda.boot.tenant.core.annotation.ConditionalOnTenantEnabled;
import cn.phecda.boot.tenant.core.liquibase.TenantSpringLiquibase;
import cn.phecda.boot.tenant.core.properties.TenantProperties;
import cn.phecda.boot.tenant.core.service.TenantDataSourceService;
import cn.phecda.boot.tenant.core.spring.TenantRoutingDataSource;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.annotation.PostConstruct;
import liquibase.integration.spring.SpringLiquibase;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

/**
 * <p> 租户主配置 </p>
 *
 * @author : wanpinwei
 */
@Slf4j
@ConditionalOnTenantEnabled
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TenantProperties.class)
public class TenantCoreConfiguration {

    @PostConstruct
    public void postConstruct() {
        log.info("|Phecda Boot Tenant|- Tenant Core Configuration");
    }

    @ConditionalOnDatabaseStrategy
    @Configuration(proxyBeanMethods = false)
    public static class TenantDatabaseStrategyConfiguration {
        @PostConstruct
        public void postConstruct() {
            log.info("|Phecda Boot Tenant|- Tenant Database Strategy Configuration");
        }

        @Bean
        public TenantDataSourceService tenantDataSourceService(@Qualifier("masterDataSourceProperties") DataSourceProperties masterDataSourceProperties,
                                                               TenantProperties dataTenantProperties) {
            TenantDataSourceService service = new TenantDataSourceService(masterDataSourceProperties, dataTenantProperties);
            log.trace("|Phecda Boot Tenant|- Tenant Data Source Service");
            return service;
        }

        @Bean
        @ConfigurationProperties("spring.datasource")
        public DataSourceProperties masterDataSourceProperties() {
            return new DataSourceProperties();
        }

        @Bean
        @ConfigurationProperties("spring.datasource.hikari")
        public DataSource masterDataSource(DataSourceProperties masterDataSourceProperties) {
            HikariDataSource dataSource = masterDataSourceProperties
                    .initializeDataSourceBuilder()
                    .type(HikariDataSource.class)
                    .build();
            dataSource.setPoolName("masterDataSource");
            return dataSource;
        }

        @Bean
        @Primary
        public DataSource tenantRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                                  TenantDataSourceService tenantDataSourceService) {
            TenantRoutingDataSource ds = new TenantRoutingDataSource(tenantDataSourceService, masterDataSource);
            log.trace("|Phecda Boot Tenant|- Tenant Routing Data Source");
            return ds;
        }
    }

    /**
     * 租户liquibase配置
     */
    @ConditionalOnDatabaseStrategy
    @ConditionalOnClass(SpringLiquibase.class)
    @Configuration(proxyBeanMethods = false)
    public static class TenantSpringLiquibaseConfiguration {
        @PostConstruct
        public void postConstruct() {
            log.info("|Phecda Boot Tenant|- Tenant Spring Liquibase Configuration");
        }

        @Bean
        public TenantSpringLiquibase tenantSpringLiquibase(ObjectProvider<SpringLiquibase> springLiquibase,
                                                           TenantDataSourceService tenantDataSourceService,
                                                           TenantProperties dataTenantProperties) {

            TenantSpringLiquibase liquibase = new TenantSpringLiquibase(springLiquibase.getIfAvailable(), dataTenantProperties, tenantDataSourceService);
            log.trace("|Phecda Boot Tenant|- Tenant Spring Liquibase");
            return liquibase;
        }
    }
}
